//===--- Remangler.cpp - Swift re-mangling from a demangling tree ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the remangler, which turns a demangling parse
//  tree back into a mangled string.  This is useful for tools which
//  want to extract subtrees from mangled strings.
//
//===----------------------------------------------------------------------===//

#include "polarphp/demangling/Demangler.h"
#include "polarphp/demangling/Punycode.h"
#include "polarphp/demangling/ManglingUtils.h"
#include "polarphp/demangling/ManglingMacros.h"
#include "polarphp/demangling/internal/RemanglerBase.h"
#include "polarphp/ast/Ownership.h"
#include "polarphp/global/NameStrings.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"

#include <cstdio>
#include <cstdlib>

namespace polar::demangling {

using namespace polar::mangling;
using polar::ReferenceOwnership;

[[noreturn]]
static void unreachable(const char *Message) {
   fprintf(stderr, "fatal error: %s\n", Message);
   std::abort();
}

static char getCharOfNodeText(Node *node, unsigned idx) {
   switch (node->getKind()) {
      case Node::Kind::InfixOperator:
      case Node::Kind::PrefixOperator:
      case Node::Kind::PostfixOperator:
         return mangling::translateOperatorChar(node->getText()[idx]);
      default:
         return node->getText()[idx];
   }
}

bool SubstitutionEntry::identifierEquals(Node *lhs, Node *rhs) {
   unsigned length = lhs->getText().size();
   if (rhs->getText().size() != length)
      return false;
   // The fast path.
   if (lhs->getKind() == rhs->getKind())
      return lhs->getText() == rhs->getText();
   // The slow path.
   for (unsigned i = 0; i < length; ++i) {
      if (getCharOfNodeText(lhs, i) != getCharOfNodeText(rhs, i))
         return false;
   }
   return true;
}

void SubstitutionEntry::deepHash(Node *node) {
   if (treatAsIdentifier) {
      combineHash((size_t) Node::Kind::Identifier);
      assert(node->hasText());
      switch (node->getKind()) {
         case Node::Kind::InfixOperator:
         case Node::Kind::PrefixOperator:
         case Node::Kind::PostfixOperator:
            for (char c : node->getText()) {
               combineHash((unsigned char) translateOperatorChar(c));
            }
            return;
         default:
            break;
      }
   } else {
      combineHash((size_t) node->getKind());
   }
   if (node->hasIndex()) {
      combineHash(node->getIndex());
   } else if (node->hasText()) {
      for (char c : node->getText()) {
         combineHash((unsigned char) c);
      }
   }
   for (Node *child : *node) {
      deepHash(child);
   }
}

bool SubstitutionEntry::deepEquals(Node *lhs, Node *rhs) const {
   if (lhs->getKind() != rhs->getKind())
      return false;
   if (lhs->hasIndex()) {
      if (!rhs->hasIndex())
         return false;
      if (lhs->getIndex() != rhs->getIndex())
         return false;
   } else if (lhs->hasText()) {
      if (!rhs->hasText())
         return false;
      if (lhs->getText() != rhs->getText())
         return false;
   } else if (rhs->hasIndex() || rhs->hasText()) {
      return false;
   }

   if (lhs->getNumChildren() != rhs->getNumChildren())
      return false;

   for (auto li = lhs->begin(), ri = rhs->begin(), le = lhs->end();
        li != le; ++li, ++ri) {
      if (!deepEquals(*li, *ri))
         return false;
   }

   return true;
}

// Find a substitution and return its index.
// Returns -1 if no substitution is found.
int RemanglerBase::findSubstitution(const SubstitutionEntry &entry) {
   // First search in InlineSubstitutions.
   SubstitutionEntry *result
      = std::find(InlineSubstitutions, InlineSubstitutions + NumInlineSubsts,
                  entry);
   if (result != InlineSubstitutions + NumInlineSubsts)
      return result - InlineSubstitutions;

   // Then search in OverflowSubstitutions.
   auto it = OverflowSubstitutions.find(entry);
   if (it == OverflowSubstitutions.end())
      return -1;

   return it->second;
}

void RemanglerBase::addSubstitution(const SubstitutionEntry &entry) {
   assert(findSubstitution(entry) < 0);
   if (NumInlineSubsts < InlineSubstCapacity) {
      // There is still free space in NumInlineSubsts.
      assert(OverflowSubstitutions.empty());
      InlineSubstitutions[NumInlineSubsts++] = entry;
      return;
   }
   // We have to add the entry to OverflowSubstitutions.
   unsigned Idx = OverflowSubstitutions.size() + InlineSubstCapacity;
   auto result = OverflowSubstitutions.insert({entry, Idx});
   assert(result.second);
   (void) result;
}

namespace {

class Remangler : public RemanglerBase {
   template<typename Mangler>
   friend void mangling::mangleIdentifier(Mangler &M, StringRef ident);

   friend class mangling::SubstitutionMerging;

   const bool UsePunycode = true;

   Vector<SubstitutionWord> Words;
   Vector<WordReplacement> SubstWordsInIdent;

   static const size_t MaxNumWords = 26;

   SubstitutionMerging SubstMerging;

   // A callback for resolving symbolic references.
   SymbolicResolver Resolver;

   void addSubstWordsInIdent(const WordReplacement &repl) {
      SubstWordsInIdent.push_back(repl, Factory);
   }

   void addWord(const SubstitutionWord &word) {
      Words.push_back(word, Factory);
   }

   template<typename Mangler>
   friend void mangleIdentifier(Mangler &M, StringRef ident);

   class EntityContext {
      bool AsContext = false;
   public:
      class ManglingContextRAII {
         EntityContext &Ctx;
         bool SavedValue;
      public:
         ManglingContextRAII(EntityContext &ctx)
            : Ctx(ctx), SavedValue(ctx.AsContext) {
            ctx.AsContext = true;
         }

         ~ManglingContextRAII() {
            Ctx.AsContext = SavedValue;
         }
      };
   };

   Node *getSingleChild(Node *node) {
      assert(node->getNumChildren() == 1);
      return node->getFirstChild();
   }

   Node *getSingleChild(Node *node, Node::Kind kind) {
      Node *Child = getSingleChild(node);
      assert(Child->getKind() == kind);
      return Child;
   }

   Node *skipType(Node *node) {
      if (node->getKind() == Node::Kind::Type)
         return getSingleChild(node);
      return node;
   }

   Node *getChildOfType(Node *node) {
      assert(node->getKind() == Node::Kind::Type);
      return getSingleChild(node);
   }

   void mangleIndex(Node::IndexType value) {
      if (value == 0) {
         Buffer << '_';
      } else {
         Buffer << (value - 1) << '_';
      }
   }

   void mangleDependentConformanceIndex(Node *node);

   void mangleChildNodes(Node *node) {
      mangleNodes(node->begin(), node->end());
   }

   void mangleChildNodesReversed(Node *node) {
      for (size_t Idx = 0, Num = node->getNumChildren(); Idx < Num; ++Idx) {
         mangleChildNode(node, Num - Idx - 1);
      }
   }

   void mangleListSeparator(bool &isFirstListItem) {
      if (isFirstListItem) {
         Buffer << '_';
         isFirstListItem = false;
      }
   }

   void mangleEndOfList(bool isFirstListItem) {
      if (isFirstListItem)
         Buffer << 'y';
   }

   void mangleNodes(Node::iterator i, Node::iterator e) {
      for (; i != e; ++i) {
         mangle(*i);
      }
   }

   void mangleSingleChildNode(Node *node) {
      assert(node->getNumChildren() == 1);
      mangle(*node->begin());
   }

   void mangleChildNode(Node *node, unsigned index) {
      assert(index < node->getNumChildren());
      mangle(node->begin()[index]);
   }

   void manglePureInterface(Node *Proto) {
      Proto = skipType(Proto);
      if (mangleStandardSubstitution(Proto))
         return;

      mangleChildNodes(Proto);
   }

   void mangleInterfaceList(Node *protocols, Node *superclass,
                           bool hasExplicitAnyObject);

   bool trySubstitution(Node *node, SubstitutionEntry &entry,
                        bool treatAsIdentifier = false);

   void mangleIdentifierImpl(Node *node, bool isOperator);

   bool mangleStandardSubstitution(Node *node);

   void mangleDependentGenericParamIndex(Node *node,
                                         const char *nonZeroPrefix = "",
                                         char zeroOp = 'z');

   std::pair<int, Node *> mangleConstrainedType(Node *node);

   void mangleFunctionSignature(Node *FuncType) {
      mangleChildNodesReversed(FuncType);
   }

   void mangleAnyNominalType(Node *node);

   void mangleAnyGenericType(Node *node, StringRef TypeOp);

   void mangleGenericArgs(Node *node, char &Separator,
                          bool fullSubstitutionMap = false);

   void mangleAnyConstructor(Node *node, char kindOp);

   void mangleAbstractStorage(Node *node, StringRef accessorCode);

   void mangleAnyInterfaceConformance(Node *node);

   void mangleKeyPathThunkHelper(Node *node, StringRef op);

#define NODE(ID)                                                        \
  void mangle##ID(Node *node);
#define CONTEXT_NODE(ID)                                                \
  void mangle##ID(Node *node);                                        \
//    void mangle##ID(Node *node, EntityContext &ctx);

#include "polarphp/demangling/DemangleNodesDef.h"

public:
   Remangler(SymbolicResolver Resolver, NodeFactory &Factory)
      : RemanglerBase(Factory), Resolver(Resolver) {}

   void mangle(Node *node) {
      switch (node->getKind()) {
#define NODE(ID) case Node::Kind::ID: return mangle##ID(node);

#include "polarphp/demangling/DemangleNodesDef.h"
      }
      unreachable("bad demangling tree node");
   }
};

bool Remangler::trySubstitution(Node *node, SubstitutionEntry &entry,
                                bool treatAsIdentifier) {
   if (mangleStandardSubstitution(node))
      return true;

   // Go ahead and initialize the substitution entry.
   entry.setNode(node, treatAsIdentifier);

   int Idx = findSubstitution(entry);
   if (Idx < 0)
      return false;

   if (Idx >= 26) {
      Buffer << 'A';
      mangleIndex(Idx - 26);
      return true;
   }
   char Subst = Idx + 'A';
   if (!SubstMerging.tryMergeSubst(*this, Subst, /*isStandardSubst*/ false)) {
      Buffer << 'A' << Subst;
   }
   return true;
}

void Remangler::mangleIdentifierImpl(Node *node, bool isOperator) {
   SubstitutionEntry entry;
   if (trySubstitution(node, entry, /*treatAsIdentifier*/ true)) return;
   if (isOperator) {
      mangling::mangleIdentifier(*this,
                               mangling::translateOperator(node->getText()));
   } else {
      mangling::mangleIdentifier(*this, node->getText());
   }
   addSubstitution(entry);
}

bool Remangler::mangleStandardSubstitution(Node *node) {
   if (node->getKind() != Node::Kind::Structure
       && node->getKind() != Node::Kind::Enum
       && node->getKind() != Node::Kind::Interface)
      return false;

   Node *context = node->getFirstChild();
   if (context->getKind() != Node::Kind::Module
       || context->getText() != STDLIB_NAME)
      return false;

   // Ignore private stdlib names
   if (node->getChild(1)->getKind() != Node::Kind::Identifier)
      return false;

   if (char Subst = getStandardTypeSubst(node->getChild(1)->getText())) {
      if (!SubstMerging.tryMergeSubst(*this, Subst, /*isStandardSubst*/ true)) {
         Buffer << 'S' << Subst;
      }
      return true;
   }
   return false;
}

void Remangler::mangleDependentGenericParamIndex(Node *node,
                                                 const char *nonZeroPrefix,
                                                 char zeroOp) {
   auto depth = node->getChild(0)->getIndex();
   auto index = node->getChild(1)->getIndex();

   if (depth != 0) {
      Buffer << nonZeroPrefix << 'd';
      mangleIndex(depth - 1);
      mangleIndex(index);
      return;
   }
   if (index != 0) {
      Buffer << nonZeroPrefix;
      mangleIndex(index - 1);
      return;
   }
   // depth == index == 0
   Buffer << zeroOp;
}

std::pair<int, Node *> Remangler::mangleConstrainedType(Node *node) {
   if (node->getKind() == Node::Kind::Type)
      node = getChildOfType(node);

   SubstitutionEntry entry;
   if (trySubstitution(node, entry))
      return {-1, nullptr};

   Vector<Node *> Chain;
   while (node->getKind() == Node::Kind::DependentMemberType) {
      Chain.push_back(node->getChild(1), Factory);
      node = getChildOfType(node->getFirstChild());
   }

   if (node->getKind() != Node::Kind::DependentGenericParamType) {
      mangle(node);
      node = nullptr;
   }

   const char *ListSeparator = (Chain.size() > 1 ? "_" : "");
   for (unsigned i = 1, n = Chain.size(); i <= n; ++i) {
      Node *DepAssocTyRef = Chain[n - i];
      mangle(DepAssocTyRef);
      Buffer << ListSeparator;
      ListSeparator = "";
   }
   if (!Chain.empty())
      addSubstitution(entry);
   return {(int) Chain.size(), node};
}

void Remangler::mangleAnyGenericType(Node *node, StringRef TypeOp) {
   SubstitutionEntry entry;
   if (trySubstitution(node, entry)) return;
   mangleChildNodes(node);
   Buffer << TypeOp;
   addSubstitution(entry);
}

void Remangler::mangleAnyNominalType(Node *node) {
   if (isSpecialized(node)) {
      SubstitutionEntry entry;
      if (trySubstitution(node, entry))
         return;

      NodePointer unboundType = getUnspecialized(node, Factory);
      mangleAnyNominalType(unboundType);
      char Separator = 'y';
      mangleGenericArgs(node, Separator);

      if (node->getNumChildren() == 3) {
         // Retroactive conformances.
         auto listNode = node->getChild(2);
         for (size_t Idx = 0, Num = listNode->getNumChildren(); Idx < Num; ++Idx) {
            mangle(listNode->getChild(Idx));
         }
      }

      Buffer << 'G';
      addSubstitution(entry);
      return;
   }
   switch (node->getKind()) {
      case Node::Kind::Structure:
         return mangleAnyGenericType(node, "V");
      case Node::Kind::Enum:
         return mangleAnyGenericType(node, "O");
      case Node::Kind::Class:
         return mangleAnyGenericType(node, "C");
      case Node::Kind::OtherNominalType:
         return mangleAnyGenericType(node, "XY");
      case Node::Kind::TypeAlias:
         return mangleAnyGenericType(node, "a");
      default:
         unreachable("bad nominal type kind");
   }
}

void Remangler::mangleGenericArgs(Node *node, char &Separator,
                                  bool fullSubstitutionMap) {
   switch (node->getKind()) {
      case Node::Kind::Structure:
      case Node::Kind::Enum:
      case Node::Kind::Class:
      case Node::Kind::TypeAlias:
         if (node->getKind() == Node::Kind::TypeAlias)
            fullSubstitutionMap = true;

         mangleGenericArgs(node->getChild(0), Separator,
                           fullSubstitutionMap);
         Buffer << Separator;
         Separator = '_';
         break;

      case Node::Kind::Function:
      case Node::Kind::Getter:
      case Node::Kind::Setter:
      case Node::Kind::WillSet:
      case Node::Kind::DidSet:
      case Node::Kind::ReadAccessor:
      case Node::Kind::ModifyAccessor:
      case Node::Kind::UnsafeAddressor:
      case Node::Kind::UnsafeMutableAddressor:
      case Node::Kind::Allocator:
      case Node::Kind::Constructor:
      case Node::Kind::Destructor:
      case Node::Kind::Variable:
      case Node::Kind::Subscript:
      case Node::Kind::ExplicitClosure:
      case Node::Kind::ImplicitClosure:
      case Node::Kind::DefaultArgumentInitializer:
      case Node::Kind::Initializer:
      case Node::Kind::PropertyWrapperBackingInitializer:
         if (!fullSubstitutionMap)
            break;

         mangleGenericArgs(node->getChild(0), Separator,
                           fullSubstitutionMap);
         if (demangling::nodeConsumesGenericArgs(node)) {
            Buffer << Separator;
            Separator = '_';
         }
         break;

      case Node::Kind::BoundGenericOtherNominalType:
      case Node::Kind::BoundGenericStructure:
      case Node::Kind::BoundGenericEnum:
      case Node::Kind::BoundGenericClass:
      case Node::Kind::BoundGenericInterface:
      case Node::Kind::BoundGenericTypeAlias: {
         if (node->getKind() == Node::Kind::BoundGenericTypeAlias)
            fullSubstitutionMap = true;

         NodePointer unboundType = node->getChild(0);
         assert(unboundType->getKind() == Node::Kind::Type);
         NodePointer nominalType = unboundType->getChild(0);
         NodePointer parentOrModule = nominalType->getChild(0);
         mangleGenericArgs(parentOrModule, Separator,
                           fullSubstitutionMap);
         Buffer << Separator;
         Separator = '_';
         mangleChildNodes(node->getChild(1));
         break;
      }

      case Node::Kind::BoundGenericFunction: {
         fullSubstitutionMap = true;

         NodePointer unboundFunction = node->getChild(0);
         assert(unboundFunction->getKind() == Node::Kind::Function ||
                unboundFunction->getKind() == Node::Kind::Constructor);
         NodePointer parentOrModule = unboundFunction->getChild(0);
         mangleGenericArgs(parentOrModule, Separator,
                           fullSubstitutionMap);
         Buffer << Separator;
         Separator = '_';
         mangleChildNodes(node->getChild(1));
         break;
      }

      case Node::Kind::Extension:
         mangleGenericArgs(node->getChild(1), Separator,
                           fullSubstitutionMap);
         break;

      default:
         break;
   }
}

void Remangler::mangleAbstractStorage(Node *node, StringRef accessorCode) {
   mangleChildNodes(node);
   switch (node->getKind()) {
      case Node::Kind::Subscript:
         Buffer << "i";
         break;
      case Node::Kind::Variable:
         Buffer << "v";
         break;
      default:
         unreachable("Not a storage node");
   }
   Buffer << accessorCode;
}

void Remangler::mangleAllocator(Node *node) {
   mangleAnyConstructor(node, 'C');
}

void Remangler::mangleArgumentTuple(Node *node) {
   Node *Child = skipType(getSingleChild(node));
   if (Child->getKind() == Node::Kind::Tuple &&
       Child->getNumChildren() == 0) {
      Buffer << 'y';
      return;
   }
   mangle(Child);
}

void Remangler::mangleAssociatedType(Node *node) {
   unreachable("unsupported node");
}

void Remangler::mangleAssociatedTypeRef(Node *node) {
   SubstitutionEntry entry;
   if (trySubstitution(node, entry)) return;
   mangleChildNodes(node);
   Buffer << "Qa";
   addSubstitution(entry);
}

void Remangler::mangleAssociatedTypeDescriptor(Node *node) {
   mangleChildNodes(node);
   Buffer << "Tl";
}

void Remangler::mangleAssociatedConformanceDescriptor(Node *node) {
   mangle(node->getChild(0));
   mangle(node->getChild(1));
   manglePureInterface(node->getChild(2));
   Buffer << "Tn";
}

void Remangler::mangleDefaultAssociatedConformanceAccessor(Node *node) {
   mangle(node->getChild(0));
   mangle(node->getChild(1));
   manglePureInterface(node->getChild(2));
   Buffer << "TN";
}

void Remangler::mangleBaseConformanceDescriptor(Node *node) {
   mangle(node->getChild(0));
   manglePureInterface(node->getChild(1));
   Buffer << "Tb";
}

void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
   mangleChildNodes(node); // protocol conformance, identifier
   Buffer << "Wt";
}

void Remangler::mangleDefaultAssociatedTypeMetadataAccessor(Node *node) {
   mangleChildNodes(node); // protocol conformance, identifier
   Buffer << "TM";
}

void Remangler::mangleAssociatedTypeWitnessTableAccessor(Node *node) {
   mangleChildNodes(node); // protocol conformance, type, protocol
   Buffer << "WT";
}

void Remangler::mangleBaseWitnessTableAccessor(Node *node) {
   mangleChildNodes(node); // protocol conformance, protocol
   Buffer << "Wb";
}

void Remangler::mangleAutoClosureType(Node *node) {
   mangleChildNodesReversed(node); // argument tuple, result type
   Buffer << "XK";
}

void Remangler::mangleEscapingAutoClosureType(Node *node) {
   mangleChildNodesReversed(node); // argument tuple, result type
   Buffer << "XA";
}

void Remangler::mangleNoEscapeFunctionType(Node *node) {
   mangleChildNodesReversed(node); // argument tuple, result type
   Buffer << "XE";
}

void Remangler::mangleBoundGenericClass(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleBoundGenericEnum(Node *node) {
   Node *Enum = node->getChild(0)->getChild(0);
   assert(Enum->getKind() == Node::Kind::Enum);
   Node *Mod = Enum->getChild(0);
   Node *Id = Enum->getChild(1);
   if (Mod->getKind() == Node::Kind::Module && Mod->getText() == STDLIB_NAME &&
       Id->getKind() == Node::Kind::Identifier && Id->getText() == "Optional") {
      SubstitutionEntry entry;
      if (trySubstitution(node, entry))
         return;
      mangleSingleChildNode(node->getChild(1));
      Buffer << "Sg";
      addSubstitution(entry);
      return;
   }
   mangleAnyNominalType(node);
}

void Remangler::mangleBoundGenericStructure(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleBoundGenericOtherNominalType(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleBoundGenericInterface(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleBoundGenericTypeAlias(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleBoundGenericFunction(Node *node) {
   SubstitutionEntry entry;
   if (trySubstitution(node, entry))
      return;

   NodePointer unboundFunction = getUnspecialized(node, Factory);
   mangleFunction(unboundFunction);
   char Separator = 'y';
   mangleGenericArgs(node, Separator);
   Buffer << 'G';
   addSubstitution(entry);
}

void Remangler::mangleBuiltinTypeName(Node *node) {
   Buffer << 'B';
   StringRef text = node->getText();

   if (text == BUILTIN_TYPE_NAME_BRIDGEOBJECT) {
      Buffer << 'b';
   } else if (text == BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER) {
      Buffer << 'B';
   } else if (text == BUILTIN_TYPE_NAME_UNKNOWNOBJECT) {
      Buffer << 'O';
   } else if (text == BUILTIN_TYPE_NAME_NATIVEOBJECT) {
      Buffer << 'o';
   } else if (text == BUILTIN_TYPE_NAME_RAWPOINTER) {
      Buffer << 'p';
   } else if (text == BUILTIN_TYPE_NAME_PILTOKEN) {
      Buffer << 't';
   } else if (text == BUILTIN_TYPE_NAME_INTLITERAL) {
      Buffer << 'I';
   } else if (text == BUILTIN_TYPE_NAME_WORD) {
      Buffer << 'w';
   } else if (text.consume_front(BUILTIN_TYPE_NAME_INT)) {
      Buffer << 'i' << text << '_';
   } else if (text.consume_front(BUILTIN_TYPE_NAME_FLOAT)) {
      Buffer << 'f' << text << '_';
   } else if (text.consume_front(BUILTIN_TYPE_NAME_VEC)) {
      // Avoid using StringRef::split because its definition is not
      // provided in the header so that it requires linking with libSupport.a.
      size_t splitIdx = text.find('x');
      auto element = text.substr(splitIdx).substr(1);
      if (element == "RawPointer") {
         Buffer << 'p';
      } else if (element.consume_front("FPIEEE")) {
         Buffer << 'f' << element << '_';
      } else if (element.consume_front("Int")) {
         Buffer << 'i' << element << '_';
      } else {
         unreachable("unexpected builtin vector type");
      }
      Buffer << "Bv" << text.substr(0, splitIdx) << '_';
   } else {
      unreachable("unexpected builtin type");
   }
}

void Remangler::mangleCFunctionPointer(Node *node) {
   mangleChildNodesReversed(node); // argument tuple, result type
   Buffer << "XC";
}

void Remangler::mangleClass(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleAnyConstructor(Node *node, char kindOp) {
   mangleChildNodes(node);
   Buffer << "f" << kindOp;
}

void Remangler::mangleConstructor(Node *node) {
   mangleAnyConstructor(node, 'c');
}

void Remangler::mangleCoroutineContinuationPrototype(Node *node) {
   mangleChildNodes(node);
   Buffer << "TC";
}

void Remangler::mangleDeallocator(Node *node) {
   mangleChildNodes(node);
   Buffer << "fD";
}

void Remangler::mangleDeclContext(Node *node) {
   mangleSingleChildNode(node);
}

void Remangler::mangleDefaultArgumentInitializer(Node *node) {
   mangleChildNode(node, 0);
   Buffer << "fA";
   mangleChildNode(node, 1);
}

void Remangler::mangleDependentAssociatedTypeRef(Node *node) {
   mangleIdentifier(node->getFirstChild());
   if (node->getNumChildren() > 1)
      mangleChildNode(node, 1);
}

void Remangler::mangleDependentGenericConformanceRequirement(Node *node) {
   Node *ProtoOrClass = node->getChild(1);
   if (ProtoOrClass->getFirstChild()->getKind() == Node::Kind::Interface) {
      manglePureInterface(ProtoOrClass);
      auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0));
      assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second);
      switch (NumMembersAndParamIdx.first) {
         case -1:
            Buffer << "RQ";
            return; // substitution
         case 0:
            Buffer << "R";
            break;
         case 1:
            Buffer << "Rp";
            break;
         default:
            Buffer << "RP";
            break;
      }
      mangleDependentGenericParamIndex(NumMembersAndParamIdx.second);
      return;
   }
   mangle(ProtoOrClass);
   auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0));
   assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second);
   switch (NumMembersAndParamIdx.first) {
      case -1:
         Buffer << "RB";
         return; // substitution
      case 0:
         Buffer << "Rb";
         break;
      case 1:
         Buffer << "Rc";
         break;
      default:
         Buffer << "RC";
         break;
   }
   mangleDependentGenericParamIndex(NumMembersAndParamIdx.second);
   return;
}

void Remangler::mangleDependentGenericParamCount(Node *node) {
   unreachable("handled inline in DependentGenericSignature");
}

void Remangler::mangleDependentGenericParamType(Node *node) {
   if (node->getChild(0)->getIndex() == 0
       && node->getChild(1)->getIndex() == 0) {
      Buffer << 'x';
      return;
   }
   Buffer << 'q';
   mangleDependentGenericParamIndex(node);
}

void Remangler::mangleDependentGenericSameTypeRequirement(Node *node) {
   mangleChildNode(node, 1);
   auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0));
   assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second);
   switch (NumMembersAndParamIdx.first) {
      case -1:
         Buffer << "RS";
         return; // substitution
      case 0:
         Buffer << "Rs";
         break;
      case 1:
         Buffer << "Rt";
         break;
      default:
         Buffer << "RT";
         break;
   }
   mangleDependentGenericParamIndex(NumMembersAndParamIdx.second);
}

void Remangler::mangleDependentGenericLayoutRequirement(Node *node) {
   auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0));
   assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second);
   switch (NumMembersAndParamIdx.first) {
      case -1:
         Buffer << "RL";
         break; // substitution
      case 0:
         Buffer << "Rl";
         break;
      case 1:
         Buffer << "Rm";
         break;
      default:
         Buffer << "RM";
         break;
   }
   // If not a substitution, mangle the dependent generic param index.
   if (NumMembersAndParamIdx.first != -1)
      mangleDependentGenericParamIndex(NumMembersAndParamIdx.second);
   assert(node->getChild(1)->getKind() == Node::Kind::Identifier);
   assert(node->getChild(1)->getText().size() == 1);
   Buffer << node->getChild(1)->getText()[0];
   if (node->getNumChildren() >= 3)
      mangleChildNode(node, 2);
   if (node->getNumChildren() >= 4)
      mangleChildNode(node, 3);
}

void Remangler::mangleDependentGenericSignature(Node *node) {
   size_t ParamCountEnd = 0;
   for (size_t Idx = 0, Num = node->getNumChildren(); Idx < Num; Idx++) {
      Node *Child = node->getChild(Idx);
      if (Child->getKind() == Node::Kind::DependentGenericParamCount) {
         ParamCountEnd = Idx + 1;
      } else {
         // requirement
         mangleChildNode(node, Idx);
      }
   }
   // If there's only one generic param, mangle nothing.
   if (ParamCountEnd == 1 && node->getChild(0)->getIndex() == 1) {
      Buffer << 'l';
      return;
   }

   // Remangle generic params.
   Buffer << 'r';
   for (size_t Idx = 0; Idx < ParamCountEnd; ++Idx) {
      Node *Count = node->getChild(Idx);
      if (Count->getIndex() > 0) {
         mangleIndex(Count->getIndex() - 1);
      } else {
         Buffer << 'z';
      }
   }
   Buffer << 'l';
}

void Remangler::mangleDependentGenericType(Node *node) {
   mangleChildNodesReversed(node); // type, generic signature
   Buffer << 'u';
}

void Remangler::mangleDependentMemberType(Node *node) {
   auto NumMembersAndParamIdx = mangleConstrainedType(node);
   switch (NumMembersAndParamIdx.first) {
      case -1:
         break; // substitution
      case 0:
         unreachable("wrong dependent member type");
      case 1:
         Buffer << 'Q';
         if (auto dependentBase = NumMembersAndParamIdx.second) {
            mangleDependentGenericParamIndex(dependentBase, "y", 'z');
         } else {
            Buffer << 'x';
         }
         break;
      default:
         Buffer << 'Q';
         if (auto dependentBase = NumMembersAndParamIdx.second) {
            mangleDependentGenericParamIndex(dependentBase, "Y", 'Z');
         } else {
            Buffer << 'X';
         }
         break;
   }
}

void Remangler::mangleDependentPseudogenericSignature(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleDestructor(Node *node) {
   mangleChildNodes(node);
   Buffer << "fd";
}

void Remangler::mangleDidSet(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "W");
}

void Remangler::mangleDirectness(Node *node) {
   if (node->getIndex() == unsigned(Directness::Direct)) {
      Buffer << 'd';
   } else {
      assert(node->getIndex() == unsigned(Directness::Indirect));
      Buffer << 'i';
   }
}

void Remangler::mangleDynamicAttribute(Node *node) {
   Buffer << "TD";
}

void Remangler::mangleDirectMethodReferenceAttribute(Node *node) {
   Buffer << "Td";
}

void Remangler::mangleDynamicSelf(Node *node) {
   mangleSingleChildNode(node); // type
   Buffer << "XD";
}

void Remangler::mangleEnum(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleErrorType(Node *node) {
   Buffer << "Xe";
}

void Remangler::mangleExistentialMetatype(Node *node) {
   if (node->getFirstChild()->getKind() == Node::Kind::MetatypeRepresentation) {
      mangleChildNode(node, 1);
      Buffer << "Xm";
      mangleChildNode(node, 0);
   } else {
      mangleSingleChildNode(node);
      Buffer << "Xp";
   }
}

void Remangler::mangleExplicitClosure(Node *node) {
   mangleChildNode(node, 0); // context
   mangleChildNode(node, 2); // type
   Buffer << "fU";
   mangleChildNode(node, 1); // index
}

void Remangler::mangleExtension(Node *node) {
   mangleChildNode(node, 1);
   mangleChildNode(node, 0);
   if (node->getNumChildren() == 3)
      mangleChildNode(node, 2); // generic signature
   Buffer << 'E';
}

void Remangler::mangleAnonymousContext(Node *node) {
   mangleChildNode(node, 1);
   mangleChildNode(node, 0);
   if (node->getNumChildren() >= 3)
      mangleTypeList(node->getChild(2));
   Buffer << "XZ";
}

void Remangler::mangleFieldOffset(Node *node) {
   mangleChildNode(node, 1); // variable
   Buffer << "Wv";
   mangleChildNode(node, 0); // directness
}

void Remangler::mangleEnumCase(Node *node) {
   mangleSingleChildNode(node); // enum case
   Buffer << "WC";
}

void Remangler::mangleFullTypeMetadata(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mf";
}

void Remangler::mangleFunction(Node *node) {
   mangleChildNode(node, 0); // context
   mangleChildNode(node, 1); // name

   bool hasLabels = node->getChild(2)->getKind() == Node::Kind::LabelList;
   Node *FuncType = getSingleChild(node->getChild(hasLabels ? 3 : 2));

   if (hasLabels)
      mangleChildNode(node, 2); // parameter labels

   if (FuncType->getKind() == Node::Kind::DependentGenericType) {
      mangleFunctionSignature(getSingleChild(FuncType->getChild(1)));
      mangleChildNode(FuncType, 0); // generic signature
   } else {
      mangleFunctionSignature(FuncType);
   }

   Buffer << "F";
}

void Remangler::mangleFunctionSignatureSpecialization(Node *node) {
   for (NodePointer Param : *node) {
      if (Param->getKind() == Node::Kind::FunctionSignatureSpecializationParam &&
          Param->getNumChildren() > 0) {
         Node *KindNd = Param->getChild(0);
         switch (FunctionSigSpecializationParamKind(KindNd->getIndex())) {
            case FunctionSigSpecializationParamKind::ConstantPropFunction:
            case FunctionSigSpecializationParamKind::ConstantPropGlobal:
               mangleIdentifier(Param->getChild(1));
               break;
            case FunctionSigSpecializationParamKind::ConstantPropString: {
               NodePointer TextNd = Param->getChild(2);
               StringRef Text = TextNd->getText();
               if (!Text.empty() && (isDigit(Text[0]) || Text[0] == '_')) {
                  std::string Buffer = "_";
                  Buffer.append(Text.data(), Text.size());
                  TextNd = Factory.createNode(Node::Kind::Identifier, Buffer);
               }
               mangleIdentifier(TextNd);
               break;
            }
            case FunctionSigSpecializationParamKind::ClosureProp:
               mangleIdentifier(Param->getChild(1));
               for (unsigned i = 2, e = Param->getNumChildren(); i != e; ++i) {
                  mangleType(Param->getChild(i));
               }
               break;
            default:
               break;
         }
      }
   }
   Buffer << "Tf";
   bool returnValMangled = false;
   for (NodePointer Child : *node) {
      if (Child->getKind() == Node::Kind::FunctionSignatureSpecializationReturn) {
         Buffer << '_';
         returnValMangled = true;
      }
      mangle(Child);

      if (Child->getKind() == Node::Kind::SpecializationPassID &&
          node->hasIndex()) {
         Buffer << node->getIndex();
      }
   }
   if (!returnValMangled)
      Buffer << "_n";
}

void Remangler::mangleFunctionSignatureSpecializationReturn(Node *node) {
   mangleFunctionSignatureSpecializationParam(node);
}

void Remangler::mangleFunctionSignatureSpecializationParam(Node *node) {
   if (!node->hasChildren()) {
      Buffer << 'n';
      return;
   }

   // The first child is always a kind that specifies the type of param that we
   // have.
   Node *KindNd = node->getChild(0);
   unsigned kindValue = KindNd->getIndex();
   auto kind = FunctionSigSpecializationParamKind(kindValue);

   switch (kind) {
      case FunctionSigSpecializationParamKind::ConstantPropFunction:
         Buffer << "pf";
         return;
      case FunctionSigSpecializationParamKind::ConstantPropGlobal:
         Buffer << "pg";
         return;
      case FunctionSigSpecializationParamKind::ConstantPropInteger:
         Buffer << "pi" << node->getChild(1)->getText();
         return;
      case FunctionSigSpecializationParamKind::ConstantPropFloat:
         Buffer << "pd" << node->getChild(1)->getText();
         return;
      case FunctionSigSpecializationParamKind::ConstantPropString: {
         Buffer << "ps";
         StringRef encodingStr = node->getChild(1)->getText();
         if (encodingStr == "u8") {
            Buffer << 'b';
         } else if (encodingStr == "u16") {
            Buffer << 'w';
         } else if (encodingStr == "objc") {
            Buffer << 'c';
         } else {
            unreachable("Unknown encoding");
         }
         return;
      }
      case FunctionSigSpecializationParamKind::ClosureProp:
         Buffer << 'c';
         return;
      case FunctionSigSpecializationParamKind::BoxToValue:
         Buffer << 'i';
         return;
      case FunctionSigSpecializationParamKind::BoxToStack:
         Buffer << 's';
         return;
      case FunctionSigSpecializationParamKind::SROA:
         Buffer << 'x';
         return;
      default:
         if (kindValue &
             unsigned(
                FunctionSigSpecializationParamKind::ExistentialToGeneric)) {
            Buffer << 'e';
            if (kindValue & unsigned(FunctionSigSpecializationParamKind::Dead))
               Buffer << 'D';
            if (kindValue &
                unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed))
               Buffer << 'G';
            if (kindValue &
                unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned))
               Buffer << 'O';
         } else if (kindValue &
                    unsigned(FunctionSigSpecializationParamKind::Dead)) {
            Buffer << 'd';
            if (kindValue &
                unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed))
               Buffer << 'G';
            if (kindValue &
                unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned))
               Buffer << 'O';
         } else if (kindValue &
                    unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) {
            Buffer << 'g';
         } else if (kindValue &
                    unsigned(
                       FunctionSigSpecializationParamKind::GuaranteedToOwned)) {
            Buffer << 'o';
         }
         if (kindValue & unsigned(FunctionSigSpecializationParamKind::SROA))
            Buffer << 'X';
         return;
   }
}

void Remangler::mangleFunctionSignatureSpecializationParamKind(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleFunctionSignatureSpecializationParamPayload(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleFunctionType(Node *node) {
   mangleFunctionSignature(node);
   Buffer << 'c';
}

void Remangler::mangleGenericInterfaceWitnessTable(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "WG";
}

void Remangler::mangleGenericInterfaceWitnessTableInstantiationFunction(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "WI";
}

void Remangler::mangleResilientInterfaceWitnessTable(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Wr";
}

void Remangler::mangleGenericPartialSpecialization(Node *node) {
   for (NodePointer Child : *node) {
      if (Child->getKind() == Node::Kind::GenericSpecializationParam) {
         mangleChildNode(Child, 0);
         break;
      }
   }
   Buffer << (node->getKind() ==
              Node::Kind::GenericPartialSpecializationNotReAbstracted ? "TP" : "Tp");
   for (NodePointer Child : *node) {
      if (Child->getKind() != Node::Kind::GenericSpecializationParam)
         mangle(Child);
   }
}

void Remangler::mangleGenericPartialSpecializationNotReAbstracted(Node *node) {
   mangleGenericPartialSpecialization(node);
}

void Remangler::mangleGenericSpecialization(Node *node) {
   bool FirstParam = true;
   for (NodePointer Child : *node) {
      if (Child->getKind() == Node::Kind::GenericSpecializationParam) {
         mangleChildNode(Child, 0);
         mangleListSeparator(FirstParam);
      }
   }
   assert(!FirstParam && "generic specialization with no substitutions");

   switch (node->getKind()) {
      case Node::Kind::GenericSpecialization:
         Buffer << "Tg";
         break;
      case Node::Kind::GenericSpecializationNotReAbstracted:
         Buffer << "TG";
         break;
      case Node::Kind::InlinedGenericFunction:
         Buffer << "Ti";
         break;
      default:
         unreachable("unsupported node");
   }

   for (NodePointer Child : *node) {
      if (Child->getKind() != Node::Kind::GenericSpecializationParam)
         mangle(Child);
   }
}

void Remangler::mangleGenericSpecializationNotReAbstracted(Node *node) {
   mangleGenericSpecialization(node);
}

void Remangler::mangleInlinedGenericFunction(Node *node) {
   mangleGenericSpecialization(node);
}


void Remangler::mangleGenericSpecializationParam(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleGenericTypeMetadataPattern(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "MP";
}

void Remangler::mangleGenericTypeParamDecl(Node *node) {
   mangleChildNodes(node);
   Buffer << "fp";
}

void Remangler::mangleGetter(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "g");
}

void Remangler::mangleGlobal(Node *node) {
   Buffer << MANGLING_PREFIX_STR;
   bool mangleInReverseOrder = false;
   for (auto Iter = node->begin(), End = node->end(); Iter != End; ++Iter) {
      Node *Child = *Iter;
      switch (Child->getKind()) {
         case Node::Kind::FunctionSignatureSpecialization:
         case Node::Kind::GenericSpecialization:
         case Node::Kind::GenericSpecializationNotReAbstracted:
         case Node::Kind::InlinedGenericFunction:
         case Node::Kind::GenericPartialSpecialization:
         case Node::Kind::GenericPartialSpecializationNotReAbstracted:
         case Node::Kind::OutlinedBridgedMethod:
         case Node::Kind::OutlinedVariable:
         case Node::Kind::ObjCAttribute:
         case Node::Kind::NonObjCAttribute:
         case Node::Kind::DynamicAttribute:
         case Node::Kind::VTableAttribute:
         case Node::Kind::DirectMethodReferenceAttribute:
         case Node::Kind::MergedFunction:
         case Node::Kind::DynamicallyReplaceableFunctionKey:
         case Node::Kind::DynamicallyReplaceableFunctionImpl:
         case Node::Kind::DynamicallyReplaceableFunctionVar:
            mangleInReverseOrder = true;
            break;
         default:
            mangle(Child);
            if (mangleInReverseOrder) {
               auto ReverseIter = Iter;
               while (ReverseIter != node->begin()) {
                  --ReverseIter;
                  mangle(*ReverseIter);
               }
               mangleInReverseOrder = false;
            }
            break;
      }
   }
}

void Remangler::mangleGlobalGetter(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "G");
}

void Remangler::mangleIdentifier(Node *node) {
   mangleIdentifierImpl(node, /*isOperator*/ false);
}

void Remangler::mangleIndex(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleUnknownIndex(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleIVarInitializer(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "fe";
}

void Remangler::mangleIVarDestroyer(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "fE";
}

void Remangler::mangleImplEscaping(Node *node) {
   Buffer << 'e';
}

void Remangler::mangleImplConvention(Node *node) {
   char ConvCh = llvm::StringSwitch<char>(node->getText())
      .Case("@callee_unowned", 'y')
      .Case("@callee_guaranteed", 'g')
      .Case("@callee_owned", 'x')
      .Default(0);
   assert(ConvCh && "invalid impl callee convention");
   Buffer << ConvCh;
}

void Remangler::mangleImplFunctionAttribute(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleImplFunctionType(Node *node) {
   const char *PseudoGeneric = "";
   Node *GenSig = nullptr;
   for (NodePointer Child : *node) {
      switch (Child->getKind()) {
         case Node::Kind::ImplParameter:
         case Node::Kind::ImplResult:
         case Node::Kind::ImplErrorResult:
            mangleChildNode(Child, 1);
            break;
         case Node::Kind::DependentPseudogenericSignature:
            PseudoGeneric = "P";
            LLVM_FALLTHROUGH;
         case Node::Kind::DependentGenericSignature:
            GenSig = Child;
            break;
         default:
            break;
      }
   }
   if (GenSig)
      mangle(GenSig);

   Buffer << 'I' << PseudoGeneric;
   for (NodePointer Child : *node) {
      switch (Child->getKind()) {
         case Node::Kind::ImplEscaping:
            Buffer << 'e';
            break;
         case Node::Kind::ImplConvention: {
            char ConvCh = llvm::StringSwitch<char>(Child->getText())
               .Case("@callee_unowned", 'y')
               .Case("@callee_guaranteed", 'g')
               .Case("@callee_owned", 'x')
               .Case("@convention(thin)", 't')
               .Default(0);
            assert(ConvCh && "invalid impl callee convention");
            Buffer << ConvCh;
            break;
         }
         case Node::Kind::ImplFunctionAttribute: {
            char FuncAttr = llvm::StringSwitch<char>(Child->getText())
               .Case("@convention(block)", 'B')
               .Case("@convention(c)", 'C')
               .Case("@convention(method)", 'M')
               .Case("@convention(objc_method)", 'O')
               .Case("@convention(closure)", 'K')
               .Case("@convention(witness_method)", 'W')
               .Default(0);
            assert(FuncAttr && "invalid impl function attribute");
            Buffer << FuncAttr;
            break;
         }
         case Node::Kind::ImplParameter: {
            char ConvCh =
               llvm::StringSwitch<char>(Child->getFirstChild()->getText())
                  .Case("@in", 'i')
                  .Case("@inout", 'l')
                  .Case("@inout_aliasable", 'b')
                  .Case("@in_guaranteed", 'n')
                  .Case("@in_constant", 'c')
                  .Case("@owned", 'x')
                  .Case("@guaranteed", 'g')
                  .Case("@deallocating", 'e')
                  .Case("@unowned", 'y')
                  .Default(0);
            assert(ConvCh && "invalid impl parameter convention");
            Buffer << ConvCh;
            break;
         }
         case Node::Kind::ImplErrorResult:
            Buffer << 'z';
            LLVM_FALLTHROUGH;
         case Node::Kind::ImplResult: {
            char ConvCh = llvm::StringSwitch<char>(Child->getFirstChild()->getText())
               .Case("@out", 'r')
               .Case("@owned", 'o')
               .Case("@unowned", 'd')
               .Case("@unowned_inner_pointer", 'u')
               .Case("@autoreleased", 'a')
               .Default(0);
            assert(ConvCh && "invalid impl parameter convention");
            Buffer << ConvCh;
            break;
         }
         default:
            break;
      }
   }
   Buffer << '_';
}

void Remangler::mangleImplicitClosure(Node *node) {
   mangleChildNode(node, 0); // context
   mangleChildNode(node, 2); // type
   Buffer << "fu";
   mangleChildNode(node, 1); // index
}

void Remangler::mangleImplParameter(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleImplResult(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleImplErrorResult(Node *node) {
   unreachable("handled inline");
}

void Remangler::mangleInOut(Node *node) {
   mangleSingleChildNode(node);
   Buffer << 'z';
}

void Remangler::mangleShared(Node *node) {
   mangleSingleChildNode(node);
   Buffer << 'h';
}

void Remangler::mangleOwned(Node *node) {
   mangleSingleChildNode(node);
   Buffer << 'n';
}

void Remangler::mangleInfixOperator(Node *node) {
   mangleIdentifierImpl(node, /*isOperator*/ true);
   Buffer << "oi";
}

void Remangler::mangleInitializer(Node *node) {
   mangleChildNodes(node);
   Buffer << "fi";
}

void Remangler::manglePropertyWrapperBackingInitializer(Node *node) {
   mangleChildNodes(node);
   Buffer << "fP";
}

void Remangler::mangleLazyInterfaceWitnessTableAccessor(Node *node) {
   mangleChildNodes(node);
   Buffer << "Wl";
}

void Remangler::mangleLazyInterfaceWitnessTableCacheVariable(Node *node) {
   mangleChildNodes(node);
   Buffer << "WL";
}

void Remangler::mangleLocalDeclName(Node *node) {
   mangleChildNode(node, 1); // identifier
   Buffer << 'L';
   mangleChildNode(node, 0); // index
}

void Remangler::mangleMaterializeForSet(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "m");
}

void Remangler::mangleMetatype(Node *node) {
   if (node->getFirstChild()->getKind() == Node::Kind::MetatypeRepresentation) {
      mangleChildNode(node, 1);
      Buffer << "XM";
      mangleChildNode(node, 0);
   } else {
      mangleSingleChildNode(node);
      Buffer << 'm';
   }
}

void Remangler::mangleMetatypeRepresentation(Node *node) {
   if (node->getText() == "@thin") {
      Buffer << 't';
   } else if (node->getText() == "@thick") {
      Buffer << 'T';
   } else if (node->getText() == "@objc_metatype") {
      Buffer << 'o';
   } else {
      unreachable("wrong metatype representation");
   }
}

void Remangler::mangleMetaclass(Node *node) {
   mangleChildNodes(node);
   Buffer << "Mm";
}

void Remangler::mangleModifyAccessor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "M");
}

void Remangler::mangleModule(Node *node) {
   if (node->getText() == STDLIB_NAME) {
      Buffer << 's';
   } else if (node->getText() == MANGLING_MODULE_OBJC) {
      Buffer << "So";
   } else if (node->getText() == MANGLING_MODULE_CLANG_IMPORTER) {
      Buffer << "SC";
   } else {
      mangleIdentifier(node);
   }
}

void Remangler::mangleNativeOwningAddressor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "lo");
}

void Remangler::mangleNativeOwningMutableAddressor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "ao");
}

void Remangler::mangleNativePinningAddressor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "lp");
}

void Remangler::mangleNativePinningMutableAddressor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "aP");
}

void Remangler::mangleClassMetadataBaseOffset(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mo";
}

void Remangler::mangleNominalTypeDescriptor(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mn";
}

void Remangler::mangleOpaqueTypeDescriptor(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "MQ";
}

void Remangler::mangleOpaqueTypeDescriptorAccessor(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mg";
}

void Remangler::mangleOpaqueTypeDescriptorAccessorImpl(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mh";
}

void Remangler::mangleOpaqueTypeDescriptorAccessorKey(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mj";
}

void Remangler::mangleOpaqueTypeDescriptorAccessorVar(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mk";
}

void Remangler::manglePropertyDescriptor(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "MV";
}

void Remangler::mangleNonObjCAttribute(Node *node) {
   Buffer << "TO";
}

void Remangler::mangleTuple(Node *node) {
   mangleTypeList(node);
   Buffer << 't';
}

void Remangler::mangleNumber(Node *node) {
   mangleIndex(node->getIndex());
}

void Remangler::mangleObjCAttribute(Node *node) {
   Buffer << "To";
}

void Remangler::mangleObjCBlock(Node *node) {
   mangleChildNodesReversed(node);
   Buffer << "XB";
}

void Remangler::mangleEscapingObjCBlock(Node *node) {
   mangleChildNodesReversed(node);
   Buffer << "XL";
}

void Remangler::mangleOwningAddressor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "lO");
}

void Remangler::mangleOwningMutableAddressor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "aO");
}

void Remangler::manglePartialApplyForwarder(Node *node) {
   mangleChildNodesReversed(node);
   Buffer << "TA";
}

void Remangler::manglePartialApplyObjCForwarder(Node *node) {
   mangleChildNodesReversed(node);
   Buffer << "Ta";
}

void Remangler::mangleMergedFunction(Node *node) {
   Buffer << "Tm";
}

void Remangler::mangleDynamicallyReplaceableFunctionImpl(Node *node) {
   Buffer << "TI";
}

void Remangler::mangleDynamicallyReplaceableFunctionKey(Node *node) {
   Buffer << "Tx";
}

void Remangler::mangleDynamicallyReplaceableFunctionVar(Node *node) {
   Buffer << "TX";
}

void Remangler::manglePostfixOperator(Node *node) {
   mangleIdentifierImpl(node, /*isOperator*/ true);
   Buffer << "oP";
}

void Remangler::manglePrefixOperator(Node *node) {
   mangleIdentifierImpl(node, /*isOperator*/ true);
   Buffer << "op";
}

void Remangler::manglePrivateDeclName(Node *node) {
   mangleChildNodesReversed(node);
   Buffer << (node->getNumChildren() == 1 ? "Ll" : "LL");
}

void Remangler::mangleInterface(Node *node) {
   mangleAnyGenericType(node, "P");
}

void Remangler::mangleRetroactiveConformance(Node *node) {
   mangleAnyInterfaceConformance(node->getChild(1));
   Buffer << 'g';
   mangleIndex(node->getChild(0)->getIndex());
}

void Remangler::mangleInterfaceConformance(Node *node) {
   Node *Ty = getChildOfType(node->getChild(0));
   Node *GenSig = nullptr;
   if (Ty->getKind() == Node::Kind::DependentGenericType) {
      GenSig = Ty->getFirstChild();
      Ty = Ty->getChild(1);
   }
   mangle(Ty);
   if (node->getNumChildren() == 4)
      mangleChildNode(node, 3);
   manglePureInterface(node->getChild(1));
   mangleChildNode(node, 2);
   if (GenSig)
      mangle(GenSig);
}

void Remangler::mangleInterfaceConformanceRefInTypeModule(Node *node) {
   manglePureInterface(node->getChild(0));
   Buffer << "HP";
}

void Remangler::mangleInterfaceConformanceRefInInterfaceModule(Node *node) {
   manglePureInterface(node->getChild(0));
   Buffer << "Hp";
}

void Remangler::mangleInterfaceConformanceRefInOtherModule(Node *node) {
   manglePureInterface(node->getChild(0));
   mangleChildNode(node, 1);
}

void Remangler::mangleConcreteInterfaceConformance(Node *node) {
   mangleType(node->getChild(0));
   mangle(node->getChild(1));
   if (node->getNumChildren() > 2)
      mangleAnyInterfaceConformanceList(node->getChild(2));
   else
      Buffer << "y";
   Buffer << "HC";
}

void Remangler::mangleDependentInterfaceConformanceRoot(Node *node) {
   mangleType(node->getChild(0));
   manglePureInterface(node->getChild(1));
   Buffer << "HD";
   mangleDependentConformanceIndex(node->getChild(2));
}

void Remangler::mangleDependentInterfaceConformanceInherited(Node *node) {
   mangleAnyInterfaceConformance(node->getChild(0));
   manglePureInterface(node->getChild(1));
   Buffer << "HI";
   mangleDependentConformanceIndex(node->getChild(2));
}

void Remangler::mangleDependentAssociatedConformance(Node *node) {
   mangleType(node->getChild(0));
   manglePureInterface(node->getChild(1));
}

void Remangler::mangleDependentInterfaceConformanceAssociated(Node *node) {
   mangleAnyInterfaceConformance(node->getChild(0));
   mangleDependentAssociatedConformance(node->getChild(1));
   Buffer << "HA";
   mangleDependentConformanceIndex(node->getChild(2));
}

void Remangler::mangleDependentConformanceIndex(Node *node) {
   assert(node->getKind() == Node::Kind::Index ||
          node->getKind() == Node::Kind::UnknownIndex);
   assert(node->hasIndex() == (node->getKind() == Node::Kind::Index));
   mangleIndex(node->hasIndex() ? node->getIndex() + 2 : 1);
}

void Remangler::mangleAnyInterfaceConformance(Node *node) {
   switch (node->getKind()) {
      case Node::Kind::ConcreteInterfaceConformance:
         return mangleConcreteInterfaceConformance(node);
      case Node::Kind::DependentInterfaceConformanceRoot:
         return mangleDependentInterfaceConformanceRoot(node);
      case Node::Kind::DependentInterfaceConformanceInherited:
         return mangleDependentInterfaceConformanceInherited(node);
      case Node::Kind::DependentInterfaceConformanceAssociated:
         return mangleDependentInterfaceConformanceAssociated(node);
      default:
         break;
   }
}

void Remangler::mangleAnyInterfaceConformanceList(Node *node) {
   bool firstElem = true;
   for (NodePointer child : *node) {
      mangleAnyInterfaceConformance(child);
      mangleListSeparator(firstElem);
   }
   mangleEndOfList(firstElem);
}

void Remangler::mangleInterfaceDescriptor(Node *node) {
   manglePureInterface(getSingleChild(node));
   Buffer << "Mp";
}

void Remangler::mangleInterfaceRequirementsBaseDescriptor(Node *node) {
   manglePureInterface(getSingleChild(node));
   Buffer << "TL";
}

void Remangler::mangleInterfaceSelfConformanceDescriptor(Node *node) {
   manglePureInterface(node->getChild(0));
   Buffer << "MS";
}

void Remangler::mangleInterfaceConformanceDescriptor(Node *node) {
   mangleInterfaceConformance(node->getChild(0));
   Buffer << "Mc";
}

void Remangler::mangleInterfaceList(Node *node, Node *superclass,
                                   bool hasExplicitAnyObject) {
   auto *protocols = getSingleChild(node, Node::Kind::TypeList);
   bool FirstElem = true;
   for (NodePointer Child : *protocols) {
      manglePureInterface(Child);
      mangleListSeparator(FirstElem);
   }
   mangleEndOfList(FirstElem);
   if (superclass) {
      mangleType(superclass);
      Buffer << "Xc";
      return;
   } else if (hasExplicitAnyObject) {
      Buffer << "Xl";
      return;
   }
   Buffer << 'p';
}

void Remangler::mangleInterfaceList(Node *node) {
   mangleInterfaceList(node, nullptr, false);
}

void Remangler::mangleInterfaceListWithClass(Node *node) {
   mangleInterfaceList(node->getChild(0),
                      node->getChild(1),
                      false);
}

void Remangler::mangleInterfaceListWithAnyObject(Node *node) {
   mangleInterfaceList(node->getChild(0), nullptr, true);
}

void Remangler::mangleInterfaceSelfConformanceWitness(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "TS";
}

void Remangler::mangleInterfaceWitness(Node *node) {
   mangleChildNodes(node);
   Buffer << "TW";
}

void Remangler::mangleInterfaceSelfConformanceWitnessTable(Node *node) {
   manglePureInterface(node->getChild(0));
   Buffer << "WS";
}

void Remangler::mangleInterfaceWitnessTable(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "WP";
}

void Remangler::mangleInterfaceWitnessTablePattern(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Wp";
}

void Remangler::mangleInterfaceWitnessTableAccessor(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Wa";
}

void Remangler::mangleReabstractionThunk(Node *node) {
   mangleChildNodesReversed(node);
   Buffer << "Tr";
}

void Remangler::mangleReabstractionThunkHelper(Node *node) {
   mangleChildNodesReversed(node);
   Buffer << "TR";
}

void Remangler::mangleReabstractionThunkHelperWithSelf(Node *node) {
   mangleChildNodesReversed(node);
   Buffer << "Ty";
}

void Remangler::mangleReadAccessor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "r");
}

void Remangler::mangleKeyPathThunkHelper(Node *node, StringRef op) {
   for (NodePointer Child : *node)
      if (Child->getKind() != Node::Kind::IsSerialized)
         mangle(Child);
   Buffer << op;
   for (NodePointer Child : *node)
      if (Child->getKind() == Node::Kind::IsSerialized)
         mangle(Child);
}

void Remangler::mangleKeyPathGetterThunkHelper(Node *node) {
   mangleKeyPathThunkHelper(node, "TK");
}

void Remangler::mangleKeyPathSetterThunkHelper(Node *node) {
   mangleKeyPathThunkHelper(node, "Tk");
}

void Remangler::mangleKeyPathEqualsThunkHelper(Node *node) {
   mangleKeyPathThunkHelper(node, "TH");
}

void Remangler::mangleKeyPathHashThunkHelper(Node *node) {
   mangleKeyPathThunkHelper(node, "Th");
}

void Remangler::mangleReturnType(Node *node) {
   mangleArgumentTuple(node);
}

void Remangler::mangleRelatedEntityDeclName(Node *node) {
   mangleChildNode(node, 1);
   NodePointer kindNode = node->getFirstChild();
   if (kindNode->getText().size() != 1)
      unreachable("cannot handle multi-byte related entities");
   Buffer << "L" << kindNode->getText();
}

void Remangler::manglePILBoxType(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Xb";
}

void Remangler::mangleSetter(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "s");
}

void Remangler::mangleSpecializationPassID(Node *node) {
   Buffer << node->getIndex();
}

void Remangler::mangleIsSerialized(Node *node) {
   Buffer << 'q';
}

void Remangler::mangleStatic(Node *node) {
   mangleSingleChildNode(node);
   Buffer << 'Z';
}

void Remangler::mangleOtherNominalType(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleStructure(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleSubscript(Node *node) {
   mangleAbstractStorage(node, "p");
}

void Remangler::mangleSuffix(Node *node) {
   // Just add the suffix back on.
   Buffer << node->getText();
}

void Remangler::mangleThinFunctionType(Node *node) {
   mangleFunctionSignature(node);
   Buffer << "Xf";
}

void Remangler::mangleTupleElement(Node *node) {
   mangleChildNodesReversed(node); // tuple type, element name?
}

void Remangler::mangleTupleElementName(Node *node) {
   mangleIdentifier(node);
}

void Remangler::mangleType(Node *node) {
   mangleSingleChildNode(node);
}

void Remangler::mangleTypeAlias(Node *node) {
   mangleAnyNominalType(node);
}

void Remangler::mangleTypeList(Node *node) {
   bool FirstElem = true;
   for (size_t Idx = 0, Num = node->getNumChildren(); Idx < Num; ++Idx) {
      mangleChildNode(node, Idx);
      mangleListSeparator(FirstElem);
   }
   mangleEndOfList(FirstElem);
}

void Remangler::mangleLabelList(Node *node) {
   if (node->getNumChildren() == 0)
      Buffer << 'y';
   else
      mangleChildNodes(node);
}

void Remangler::mangleTypeMangling(Node *node) {
   mangleChildNodes(node);
   Buffer << 'D';
}

void Remangler::mangleTypeMetadata(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "N";
}

void Remangler::mangleTypeMetadataAccessFunction(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Ma";
}

void Remangler::mangleTypeMetadataInstantiationCache(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "MI";
}

void Remangler::mangleTypeMetadataInstantiationFunction(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mi";
}

void Remangler::mangleTypeMetadataSingletonInitializationCache(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Ml";
}

void Remangler::mangleTypeMetadataCompletionFunction(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mr";
}

void Remangler::mangleTypeMetadataDemanglingCache(Node *node) {
   mangleChildNodes(node);
   Buffer << "MD";
}

void Remangler::mangleTypeMetadataLazyCache(Node *node) {
   mangleChildNodes(node);
   Buffer << "ML";
}

void Remangler::mangleUncurriedFunctionType(Node *node) {
   mangleFunctionSignature(node);
   // mangling as regular function type (there is no "uncurried function type"
   // in the new mangling scheme).
   Buffer << 'c';
}

void Remangler::mangleUnsafeAddressor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "lu");
}

void Remangler::mangleUnsafeMutableAddressor(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "au");
}

void Remangler::mangleValueWitness(Node *node) {
   mangleChildNode(node, 1); // type
   const char *Code = nullptr;
   switch (ValueWitnessKind(node->getFirstChild()->getIndex())) {
#define VALUE_WITNESS(MANGLING, NAME) \
    case ValueWitnessKind::NAME: Code = #MANGLING; break;

#include "polarphp/demangling/ValueWitnessManglingDef.h"
   }
   Buffer << 'w' << Code;
}

void Remangler::mangleValueWitnessTable(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "WV";
}

void Remangler::mangleVariable(Node *node) {
   mangleAbstractStorage(node, "p");
}

void Remangler::mangleVTableAttribute(Node *node) {
   unreachable("Old-fashioned vtable thunk in new mangling format");
}

void Remangler::mangleVTableThunk(Node *node) {
   mangleChildNodes(node);
   Buffer << "TV";
}

#define REF_STORAGE(Name, ...) \
  void Remangler::mangle##Name(Node *node) { \
    mangleSingleChildNode(node); \
    Buffer << manglingOf(ReferenceOwnership::Name); \
  }

#include "polarphp/ast/ReferenceStorageDef.h"

void Remangler::mangleWillSet(Node *node) {
   mangleAbstractStorage(node->getFirstChild(), "w");
}

void Remangler::mangleReflectionMetadataBuiltinDescriptor(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "MB";
}

void Remangler::mangleReflectionMetadataFieldDescriptor(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "MF";
}

void Remangler::mangleReflectionMetadataAssocTypeDescriptor(Node *node) {
   mangleSingleChildNode(node); // protocol-conformance
   Buffer << "MA";
}

void Remangler::mangleReflectionMetadataSuperclassDescriptor(Node *node) {
   mangleSingleChildNode(node); // protocol-conformance
   Buffer << "MC";
}

void Remangler::mangleCurryThunk(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Tc";
}

void Remangler::mangleDispatchThunk(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Tj";
}

void Remangler::mangleMethodDescriptor(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Tq";
}

void Remangler::mangleMethodLookupFunction(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mu";
}

void Remangler::mangleObjCMetadataUpdateFunction(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "MU";
}

void Remangler::mangleObjCResilientClassStub(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Ms";
}

void Remangler::mangleFullObjCResilientClassStub(Node *node) {
   mangleSingleChildNode(node);
   Buffer << "Mt";
}

void Remangler::mangleThrowsAnnotation(Node *node) {
   Buffer << 'K';
}

void Remangler::mangleEmptyList(Node *node) {
   Buffer << 'y';
}

void Remangler::mangleFirstElementMarker(Node *node) {
   Buffer << '_';
}

void Remangler::mangleVariadicMarker(Node *node) {
   Buffer << 'd';
}

void Remangler::mangleOutlinedCopy(Node *node) {
   mangleChildNodes(node);
   Buffer << "WOy";
}

void Remangler::mangleOutlinedConsume(Node *node) {
   mangleChildNodes(node);
   Buffer << "WOe";
}

void Remangler::mangleOutlinedRetain(Node *node) {
   mangleChildNodes(node);
   Buffer << "WOr";
}

void Remangler::mangleOutlinedRelease(Node *node) {
   mangleChildNodes(node);
   Buffer << "WOs";
}

void Remangler::mangleOutlinedInitializeWithTake(Node *node) {
   mangleChildNodes(node);
   Buffer << "WOb";
}

void Remangler::mangleOutlinedInitializeWithCopy(Node *node) {
   mangleChildNodes(node);
   Buffer << "WOc";
}

void Remangler::mangleOutlinedAssignWithTake(Node *node) {
   mangleChildNodes(node);
   Buffer << "WOd";
}

void Remangler::mangleOutlinedAssignWithCopy(Node *node) {
   mangleChildNodes(node);
   Buffer << "WOf";
}

void Remangler::mangleOutlinedDestroy(Node *node) {
   mangleChildNodes(node);
   Buffer << "WOh";
}

void Remangler::mangleOutlinedVariable(Node *node) {
   Buffer << "Tv";
   mangleIndex(node->getIndex());
}

void Remangler::mangleOutlinedBridgedMethod(Node *node) {
   Buffer << "Te";
   Buffer << node->getText();
   Buffer << "_";
}

void Remangler::manglePILBoxTypeWithLayout(Node *node) {
   assert(node->getNumChildren() == 1 || node->getNumChildren() == 3);
   assert(node->getChild(0)->getKind() == Node::Kind::PILBoxLayout);
   auto layout = node->getChild(0);
   auto layoutTypeList = Factory.createNode(Node::Kind::TypeList);
   for (unsigned i = 0, e = layout->getNumChildren(); i < e; ++i) {
      assert(layout->getChild(i)->getKind() == Node::Kind::PILBoxImmutableField
             || layout->getChild(i)->getKind() == Node::Kind::PILBoxMutableField);
      auto field = layout->getChild(i);
      assert(field->getNumChildren() == 1
             && field->getChild(0)->getKind() == Node::Kind::Type);
      auto fieldType = field->getChild(0);
      // 'inout' mangling is used to represent mutable fields.
      if (field->getKind() == Node::Kind::PILBoxMutableField) {
         auto inout = Factory.createNode(Node::Kind::InOut);
         inout->addChild(fieldType->getChild(0), Factory);
         fieldType = Factory.createNode(Node::Kind::Type);
         fieldType->addChild(inout, Factory);
      }
      layoutTypeList->addChild(fieldType, Factory);
   }
   mangleTypeList(layoutTypeList);

   if (node->getNumChildren() == 3) {
      auto signature = node->getChild(1);
      auto genericArgs = node->getChild(2);
      assert(signature->getKind() == Node::Kind::DependentGenericSignature);
      assert(genericArgs->getKind() == Node::Kind::TypeList);
      mangleTypeList(genericArgs);
      mangleDependentGenericSignature(signature);
      Buffer << "XX";
   } else {
      Buffer << "Xx";
   }
}

void Remangler::manglePILBoxLayout(Node *node) {
   unreachable("should be part of PILBoxTypeWithLayout");
}

void Remangler::manglePILBoxMutableField(Node *node) {
   unreachable("should be part of PILBoxTypeWithLayout");
}

void Remangler::manglePILBoxImmutableField(Node *node) {
   unreachable("should be part of PILBoxTypeWithLayout");
}

void Remangler::mangleAssocTypePath(Node *node) {
   bool FirstElem = true;
   for (NodePointer Child : *node) {
      mangle(Child);
      mangleListSeparator(FirstElem);
   }
}

void Remangler::mangleModuleDescriptor(Node *node) {
   mangle(node->getChild(0));
   Buffer << "MXM";
}

void Remangler::mangleExtensionDescriptor(Node *node) {
   mangle(node->getChild(0));
   Buffer << "MXE";
}

void Remangler::mangleAnonymousDescriptor(Node *node) {
   mangle(node->getChild(0));
   if (node->getNumChildren() == 1) {
      Buffer << "MXX";
   } else {
      mangleIdentifier(node->getChild(1));
      Buffer << "MXY";
   }
}

void Remangler::mangleAssociatedTypeGenericParamRef(Node *node) {
   mangleType(node->getChild(0));
   mangleAssocTypePath(node->getChild(1));
   Buffer << "MXA";
}

void Remangler::mangleTypeSymbolicReference(Node *node) {
   return mangle(Resolver(SymbolicReferenceKind::Context,
                          (const void *) node->getIndex()));
}

void Remangler::mangleInterfaceSymbolicReference(Node *node) {
   return mangle(Resolver(SymbolicReferenceKind::Context,
                          (const void *) node->getIndex()));
}

void Remangler::mangleOpaqueTypeDescriptorSymbolicReference(Node *node) {
   return mangle(Resolver(SymbolicReferenceKind::Context,
                          (const void *) node->getIndex()));
}

void Remangler::mangleSugaredOptional(Node *node) {
   mangleType(node->getChild(0));
   Buffer << "XSq";
}

void Remangler::mangleSugaredArray(Node *node) {
   mangleType(node->getChild(0));
   Buffer << "XSa";
}

void Remangler::mangleSugaredDictionary(Node *node) {
   mangleType(node->getChild(0));
   mangleType(node->getChild(1));
   Buffer << "XSD";
}

void Remangler::mangleSugaredParen(Node *node) {
   mangleType(node->getChild(0));
   Buffer << "XSp";
}

void Remangler::mangleOpaqueReturnType(Node *node) {
   Buffer << "Qr";
}

void Remangler::mangleOpaqueReturnTypeOf(Node *node) {
   mangle(node->getChild(0));
   Buffer << "QO";
}

void Remangler::mangleOpaqueType(Node *node) {
   SubstitutionEntry entry;
   if (trySubstitution(node, entry)) return;

   mangle(node->getChild(0));
   auto boundGenerics = node->getChild(2);
   for (unsigned i = 0; i < boundGenerics->getNumChildren(); ++i) {
      Buffer << (i == 0 ? 'y' : '_');
      mangleChildNodes(boundGenerics->getChild(i));
   }
   if (node->getNumChildren() >= 4) {
      auto retroactiveConformances = node->getChild(3);
      for (unsigned i = 0; i < retroactiveConformances->getNumChildren(); ++i) {
         mangle(retroactiveConformances->getChild(i));
      }
   }
   Buffer << "Qo";
   mangleIndex(node->getChild(1)->getIndex());

   addSubstitution(entry);
}

void Remangler::mangleAccessorFunctionReference(Node *node) {
   unreachable("can't remangle");
}

} // anonymous namespace

/// The top-level interface to the remangler.
std::string mangleNode(NodePointer node) {
   return mangleNode(node, [](SymbolicReferenceKind, const void *) -> NodePointer {
      unreachable("should not try to mangle a symbolic reference; "
                  "resolve it to a non-symbolic demangling tree instead");
   });
}

std::string mangleNode(NodePointer node, SymbolicResolver resolver) {
   if (!node) return "";

   NodeFactory Factory;
   Remangler remangler(resolver, Factory);
   remangler.mangle(node);

   return remangler.str();
}

llvm::StringRef mangleNode(NodePointer node, SymbolicResolver resolver,
                     NodeFactory &Factory) {
   if (!node)
      return StringRef();

   Remangler remangler(resolver, Factory);
   remangler.mangle(node);

   return remangler.getBufferStr();
}

bool isSpecialized(Node *node) {
   switch (node->getKind()) {
      case Node::Kind::BoundGenericStructure:
      case Node::Kind::BoundGenericEnum:
      case Node::Kind::BoundGenericClass:
      case Node::Kind::BoundGenericOtherNominalType:
      case Node::Kind::BoundGenericTypeAlias:
      case Node::Kind::BoundGenericInterface:
      case Node::Kind::BoundGenericFunction:
         return true;

      case Node::Kind::Structure:
      case Node::Kind::Enum:
      case Node::Kind::Class:
      case Node::Kind::TypeAlias:
      case Node::Kind::OtherNominalType:
      case Node::Kind::Interface:
      case Node::Kind::Function:
      case Node::Kind::Allocator:
      case Node::Kind::Constructor:
      case Node::Kind::Destructor:
      case Node::Kind::Variable:
      case Node::Kind::Subscript:
      case Node::Kind::ExplicitClosure:
      case Node::Kind::ImplicitClosure:
      case Node::Kind::Initializer:
      case Node::Kind::PropertyWrapperBackingInitializer:
      case Node::Kind::DefaultArgumentInitializer:
      case Node::Kind::Getter:
      case Node::Kind::Setter:
      case Node::Kind::WillSet:
      case Node::Kind::DidSet:
      case Node::Kind::ReadAccessor:
      case Node::Kind::ModifyAccessor:
      case Node::Kind::UnsafeAddressor:
      case Node::Kind::UnsafeMutableAddressor:
         return isSpecialized(node->getChild(0));

      case Node::Kind::Extension:
         return isSpecialized(node->getChild(1));

      default:
         return false;
   }
}

NodePointer getUnspecialized(Node *node, NodeFactory &Factory) {
   unsigned NumToCopy = 2;
   switch (node->getKind()) {
      case Node::Kind::Function:
      case Node::Kind::Getter:
      case Node::Kind::Setter:
      case Node::Kind::WillSet:
      case Node::Kind::DidSet:
      case Node::Kind::ReadAccessor:
      case Node::Kind::ModifyAccessor:
      case Node::Kind::UnsafeAddressor:
      case Node::Kind::UnsafeMutableAddressor:
      case Node::Kind::Allocator:
      case Node::Kind::Constructor:
      case Node::Kind::Destructor:
      case Node::Kind::Variable:
      case Node::Kind::Subscript:
      case Node::Kind::ExplicitClosure:
      case Node::Kind::ImplicitClosure:
      case Node::Kind::Initializer:
      case Node::Kind::PropertyWrapperBackingInitializer:
      case Node::Kind::DefaultArgumentInitializer:
         NumToCopy = node->getNumChildren();
         LLVM_FALLTHROUGH;
      case Node::Kind::Structure:
      case Node::Kind::Enum:
      case Node::Kind::Class:
      case Node::Kind::TypeAlias:
      case Node::Kind::OtherNominalType: {
         NodePointer result = Factory.createNode(node->getKind());
         NodePointer parentOrModule = node->getChild(0);
         if (isSpecialized(parentOrModule))
            parentOrModule = getUnspecialized(parentOrModule, Factory);
         result->addChild(parentOrModule, Factory);
         for (unsigned Idx = 1; Idx < NumToCopy; ++Idx) {
            result->addChild(node->getChild(Idx), Factory);
         }
         return result;
      }

      case Node::Kind::BoundGenericStructure:
      case Node::Kind::BoundGenericEnum:
      case Node::Kind::BoundGenericClass:
      case Node::Kind::BoundGenericInterface:
      case Node::Kind::BoundGenericOtherNominalType:
      case Node::Kind::BoundGenericTypeAlias: {
         NodePointer unboundType = node->getChild(0);
         assert(unboundType->getKind() == Node::Kind::Type);
         NodePointer nominalType = unboundType->getChild(0);
         if (isSpecialized(nominalType))
            return getUnspecialized(nominalType, Factory);
         return nominalType;
      }

      case Node::Kind::BoundGenericFunction: {
         NodePointer unboundFunction = node->getChild(0);
         assert(unboundFunction->getKind() == Node::Kind::Function ||
                unboundFunction->getKind() == Node::Kind::Constructor);
         if (isSpecialized(unboundFunction))
            return getUnspecialized(unboundFunction, Factory);
         return unboundFunction;
      }

      case Node::Kind::Extension: {
         NodePointer parent = node->getChild(1);
         if (!isSpecialized(parent))
            return node;
         NodePointer result = Factory.createNode(Node::Kind::Extension);
         result->addChild(node->getFirstChild(), Factory);
         result->addChild(getUnspecialized(parent, Factory), Factory);
         if (node->getNumChildren() == 3) {
            // Add the generic signature of the extension.
            result->addChild(node->getChild(2), Factory);
         }
         return result;
      }
      default:
         unreachable("bad nominal type kind");
   }
}

} // polar::demangling